/*!
  @file   MatrixTypes.hpp
  @author Jared Marsau
  @author Hamza M. Hutchinson
  @date   03/01/2009
  @brief  
    This source file implements both 3x3 and 4x4 matrix types.
*/

#include "MatrixTypes.hpp"
#include "RichAssert.hpp"

namespace VectorTypes
{
  //////////////////////////////////////////////////////////////////////////////
  //Matrix3D

  /*!
  @brief
    Default contstructor does nothing.
  */
  Matrix3D::Matrix3D()
  {}

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix3D::Matrix3D(const float* arrayOfNineFloats)
  //: m_Rows[0](arrayOfNineFloats + 0),
  //  m_Rows[1](arrayOfNineFloats + 3),
  //  m_Rows[2](arrayOfNineFloats + 6)
  {
    m_Rows[0].Set(arrayOfNineFloats + 0);
    m_Rows[1].Set(arrayOfNineFloats + 3);
    m_Rows[2].Set(arrayOfNineFloats + 6);
  }

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix3D::Matrix3D(const Vector3D &row0,
                     const Vector3D &row1,
                     const Vector3D &row2)
  //: m_Rows[0](row0),
  //  m_Rows[1](row1),
  //  m_Rows[2](row2)
  {
    m_Rows[0].Set(row0);
    m_Rows[1].Set(row1);
    m_Rows[2].Set(row2);
  }

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix3D::Matrix3D(float m00, float m01, float m02,
                     float m10, float m11, float m12,
                     float m20, float m21,float  m22)
  //: m_Rows[0](m00, m01, m02),
  //  m_Rows[1](m10, m11, m12),
  //  m_Rows[2](m20, m21, m22)
  {
    m_Rows[0].Set(m00, m01, m02);
    m_Rows[1].Set(m10, m11, m12);
    m_Rows[2].Set(m20, m21, m22);
  }

  /*!
  @brief
    Assignment operator.
  */
  Matrix3D& Matrix3D::operator =  (const Matrix3D& rhs)
  {
    m_Rows[0] = rhs.m_Rows[0];
    m_Rows[1] = rhs.m_Rows[1];
    m_Rows[2] = rhs.m_Rows[2];

    return *this;
  }

  /*!
  @brief
    Adds rhs to this matrix.
  */
  Matrix3D& Matrix3D::operator += (const Matrix3D& rhs)
  {
    m_Rows[0] += rhs.m_Rows[0];
    m_Rows[1] += rhs.m_Rows[1];
    m_Rows[2] += rhs.m_Rows[2];

    return *this;
  }

  /*!
  @brief
    Subtracts rhs from this matrix.
  */
  Matrix3D& Matrix3D::operator -= (const Matrix3D& rhs)
  {
    m_Rows[0] -= rhs.m_Rows[0];
    m_Rows[1] -= rhs.m_Rows[1];
    m_Rows[2] -= rhs.m_Rows[2];

    return *this;
  }

  /*!
  @brief
    Multiplies each element of this matrix by rhs.
  */
  Matrix3D& Matrix3D::operator *= (float rhs)
  {
    m_Rows[0] *= rhs;
    m_Rows[1] *= rhs;
    m_Rows[2] *= rhs;

    return *this;
  }

  /*!
  @brief
    Divides each element of this matrix by rhs.
  */
  Matrix3D& Matrix3D::operator /= (float rhs)
  {
    m_Rows[0] /= rhs;
    m_Rows[1] /= rhs;
    m_Rows[2] /= rhs;

    return *this;
  }

  /*!
  @brief
    Returns the row of the requested index.
  */
  Vector3D&       Matrix3D::operator [] (unsigned row)
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns the row if the requested index.
  */
  const Vector3D& Matrix3D::operator [] (unsigned row) const
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns this matrix plus rhs.
  */
  Matrix3D Matrix3D::operator + (const Matrix3D& rhs) const
  {
    return Matrix3D(m_Rows[0] + rhs.m_Rows[0],
                    m_Rows[1] + rhs.m_Rows[1],
                    m_Rows[2] + rhs.m_Rows[2]);
  }

  /*!
  @brief
    Returns this matrix minus rhs.
  */
  Matrix3D Matrix3D::operator - (const Matrix3D& rhs) const
  {
    return Matrix3D(m_Rows[0] - rhs.m_Rows[0],
                    m_Rows[1] - rhs.m_Rows[1],
                    m_Rows[2] - rhs.m_Rows[2]);
  }

  /*!
  @brief
    Returns this matrix concatinated with rhs.
  */
  Matrix3D Matrix3D::operator * (const Matrix3D& rhs) const
  {
    Matrix3D m;

    m.m_Rows[0][0] = m_Rows[0][0] * rhs.m_Rows[0][0] + m_Rows[0][1] * rhs.m_Rows[1][0] + m_Rows[0][2] * rhs.m_Rows[2][0];
    m.m_Rows[0][1] = m_Rows[0][0] * rhs.m_Rows[0][1] + m_Rows[0][1] * rhs.m_Rows[1][1] + m_Rows[0][2] * rhs.m_Rows[2][1];
    m.m_Rows[0][2] = m_Rows[0][0] * rhs.m_Rows[0][2] + m_Rows[0][1] * rhs.m_Rows[1][2] + m_Rows[0][2] * rhs.m_Rows[2][2];

    m.m_Rows[1][0] = m_Rows[1][0] * rhs.m_Rows[0][0] + m_Rows[1][1] * rhs.m_Rows[1][0] + m_Rows[1][2] * rhs.m_Rows[2][0];
    m.m_Rows[1][1] = m_Rows[1][0] * rhs.m_Rows[0][1] + m_Rows[1][1] * rhs.m_Rows[1][1] + m_Rows[1][2] * rhs.m_Rows[2][1];
    m.m_Rows[1][2] = m_Rows[1][0] * rhs.m_Rows[0][2] + m_Rows[1][1] * rhs.m_Rows[1][2] + m_Rows[1][2] * rhs.m_Rows[2][2];

    m.m_Rows[2][0] = m_Rows[2][0] * rhs.m_Rows[0][0] + m_Rows[2][1] * rhs.m_Rows[1][0] + m_Rows[2][2] * rhs.m_Rows[2][0];
    m.m_Rows[2][1] = m_Rows[2][0] * rhs.m_Rows[0][1] + m_Rows[2][1] * rhs.m_Rows[1][1] + m_Rows[2][2] * rhs.m_Rows[2][1];
    m.m_Rows[2][2] = m_Rows[2][0] * rhs.m_Rows[0][2] + m_Rows[2][1] * rhs.m_Rows[1][2] + m_Rows[2][2] * rhs.m_Rows[2][2];

    return m;
  }

  /*!
  @brief
    Returns the rhs vector transformed by this matrix.
  */
  Vector3D Matrix3D::operator * (const Vector3D& rhs) const
  {
    return Vector3D(m_Rows[0] * rhs,
                    m_Rows[1] * rhs,
                    m_Rows[2] * rhs);
  }

  /*!
  @brief
    Returns this matrix scaled by rhs.
  */
  Matrix3D Matrix3D::operator * (float rhs)           const
  {
    return Matrix3D(m_Rows[0] * rhs,
                    m_Rows[1] * rhs,
                    m_Rows[2] * rhs);
  }

  /*!
  @brief
    Returns this matrix scaled by one over rhs.
  */
  Matrix3D Matrix3D::operator / (float rhs)           const
  {
    return Matrix3D(m_Rows[0] / rhs,
                    m_Rows[1] / rhs,
                    m_Rows[2] / rhs);
  }

  /*!
  @brief
    Returns true if this matrix is equal to rhs.
  */
  bool Matrix3D::operator == (const Matrix3D& rhs) const
  {
    return (m_Rows[0] == rhs.m_Rows[0] &&
            m_Rows[1] == rhs.m_Rows[1] &&
            m_Rows[2] == rhs.m_Rows[2] );
  }

  /*!
  @brief
    Returns true if this matrix is not equal to rhs.
  */
  bool Matrix3D::operator != (const Matrix3D& rhs) const
  {
    return (m_Rows[0] != rhs.m_Rows[0] ||
            m_Rows[1] != rhs.m_Rows[1] ||
            m_Rows[2] != rhs.m_Rows[2] );
  }

  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix3D::Set           (float m00, float m01, float m02,
                                        float m10, float m11, float m12,
                                        float m20, float m21,float  m22)
  {
    m_Rows[0].Set(m00, m01, m02);
    m_Rows[1].Set(m10, m11, m12);
    m_Rows[2].Set(m20, m21, m22);
  }

  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix3D::Set           (const Vector3D &row0,
                                        const Vector3D &row1,
                                        const Vector3D &row2)
  {
    m_Rows[0].Set(row0);
    m_Rows[1].Set(row1);
    m_Rows[2].Set(row2);
  }
  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix3D::Set           (const Matrix3D& source)
  {
    m_Rows[0].Set(source.m_Rows[0]);
    m_Rows[1].Set(source.m_Rows[1]);
    m_Rows[2].Set(source.m_Rows[2]);
  }

  /*!
  @brief
    Inverts this matrix.
  */
  void         Matrix3D::Invert        ()
  {
    //@todo: Implement Me!
  }

  /*!
  @brief
    Transposes this matrix.
  */
  void         Matrix3D::Transpose     ()
  {
    float temp;

    temp         = m_Rows[0][1];
    m_Rows[0][1] = m_Rows[1][0];
    m_Rows[1][0] = temp;

    temp         = m_Rows[0][2];
    m_Rows[0][2] = m_Rows[2][0];
    m_Rows[2][0] = temp;

    temp         = m_Rows[1][2];
    m_Rows[1][2] = m_Rows[2][1];
    m_Rows[2][1] = temp;
  }

  /*!
  @brief
    Returns the determinant of this matrix.
  */
  float        Matrix3D::Determinant   ()                                       const
  {
    return (m_Rows[0][0] * m_Rows[1][1] * m_Rows[2][2] -
            m_Rows[0][0] * m_Rows[1][2] * m_Rows[2][1] -
            m_Rows[0][1] * m_Rows[1][0] * m_Rows[2][2] +
            m_Rows[0][1] * m_Rows[1][2] * m_Rows[2][0] +
            m_Rows[0][2] * m_Rows[1][0] * m_Rows[2][1] -
            m_Rows[0][2] * m_Rows[1][1] * m_Rows[2][0] );
  }

  /*!
  @brief
    Returns the inverse of this matrix.
  */
  Matrix3D     Matrix3D::Inverse       ()                                       const
  {
    //@todo: Implement Me!
    return Matrix3D();
  }

  /*!
  @brief
    Returns the transpose of this matrix.
  */
  Matrix3D     Matrix3D::Transposed    ()                                       const
  {
    return Matrix3D(m_Rows[0][0], m_Rows[1][0], m_Rows[2][0],
                    m_Rows[0][1], m_Rows[1][1], m_Rows[2][1],
                    m_Rows[0][2], m_Rows[1][2], m_Rows[2][2]);
  }

  /*!
  @brief
    Calculates the determinant and returns true if it is not equal to zero,
    within some tolerance.
  */
  bool         Matrix3D::IsInvertable  (float tolerance) const
  {
    return !MathUtility::FloatEqualsZero(Determinant(), tolerance);
  }

  /*!
  @brief
    Returns the specified row in vector form.
  */
  Vector3D     Matrix3D::Row           (unsigned row)                           const
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns the specified column in vector form.
  */
  Vector3D     Matrix3D::Column        (unsigned column)                        const
  {
    return Vector3D(m_Rows[0][column],
                    m_Rows[1][column],
                    m_Rows[2][column]);
  }

  /*!
  @brief
    Returns rhs scaled by lhs.
  */
  Matrix3D operator * (float lhs, const Matrix3D& rhs)
  {
    return Matrix3D(lhs * rhs.m_Rows[0],
                    lhs * rhs.m_Rows[1],
                    lhs * rhs.m_Rows[2]);
  }




  //////////////////////////////////////////////////////////////////////////////
  //Matrix4D

  /*!
  @brief
    Default constructor does nothing.
  */
  Matrix4D::Matrix4D()
  {}

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix4D::Matrix4D(const float* arrayOfSixteenFloats)
  //: m_Rows[0](arrayOfSixteenFloats +  0),
  //  m_Rows[1](arrayOfSixteenFloats +  4),
  //  m_Rows[2](arrayOfSixteenFloats +  8),
  //  m_Rows[2](arrayOfSixteenFloats + 12)
  {
    m_Rows[0].Set(arrayOfSixteenFloats +  0);
    m_Rows[1].Set(arrayOfSixteenFloats +  4);
    m_Rows[2].Set(arrayOfSixteenFloats +  8);
    m_Rows[2].Set(arrayOfSixteenFloats + 12);
  }

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix4D::Matrix4D(const Vector4D &row0,
                     const Vector4D &row1,
                     const Vector4D &row2,
                     const Vector4D &row3)
  //: m_Rows[0](row0),
  //  m_Rows[1](row1),
  //  m_Rows[2](row2),
  //  m_Rows[3](row3)
  {
    m_Rows[0].Set(row0);
    m_Rows[1].Set(row1);
    m_Rows[2].Set(row2);
    m_Rows[3].Set(row3);
  }

  /*!
  @brief
    Initializes the matrix with the given data.
  */
  Matrix4D::Matrix4D(float m00, float m01, float m02, float m03,
                     float m10, float m11, float m12, float m13,
                     float m20, float m21,float  m22, float m23,
                     float m30, float m31, float m32, float m33)
  //: m_Rows[0](m00, m01, m02, m03),
  //  m_Rows[1](m10, m11, m12, m13),
  //  m_Rows[2](m20, m21, m22, m23),
  //  m_Rows[3](m30, m31, m32, m33)
  {
    m_Rows[0].Set(m00, m01, m02, m03);
    m_Rows[1].Set(m10, m11, m12, m13);
    m_Rows[2].Set(m20, m21, m22, m23);
    m_Rows[3].Set(m30, m31, m32, m33);
  }

  /*!
  @brief
    Assignment operator.
  */
  Matrix4D& Matrix4D::operator =  (const Matrix4D& rhs)
  {
    m_Rows[0] = rhs.m_Rows[0];
    m_Rows[1] = rhs.m_Rows[1];
    m_Rows[2] = rhs.m_Rows[2];
    m_Rows[3] = rhs.m_Rows[3];

    return *this;
  }

  /*!
  @brief
    Adds rhs to this matrix.
  */
  Matrix4D& Matrix4D::operator += (const Matrix4D& rhs)
  {
    m_Rows[0] += rhs.m_Rows[0];
    m_Rows[1] += rhs.m_Rows[1];
    m_Rows[2] += rhs.m_Rows[2];
    m_Rows[3] += rhs.m_Rows[3];

    return *this;
  }

  /*!
  @brief
    Multiplies each element of this matrix by rhs.
  */
  Matrix4D& Matrix4D::operator -= (const Matrix4D& rhs)
  {
    m_Rows[0] -= rhs.m_Rows[0];
    m_Rows[1] -= rhs.m_Rows[1];
    m_Rows[2] -= rhs.m_Rows[2];
    m_Rows[3] -= rhs.m_Rows[3];

    return *this;
  }

  /*!
  @brief
    Multiplies each element of this matrix by rhs.
  */
  Matrix4D& Matrix4D::operator *= (float rhs)
  {
    m_Rows[0] *= rhs;
    m_Rows[1] *= rhs;
    m_Rows[2] *= rhs;
    m_Rows[3] *= rhs;

    return *this;
  }

  /*!
  @brief
    Divides each element of this matrix by rhs.
  */
  Matrix4D& Matrix4D::operator /= (float rhs)
  {
    m_Rows[0] /= rhs;
    m_Rows[1] /= rhs;
    m_Rows[2] /= rhs;
    m_Rows[3] /= rhs;

    return *this;
  }

  /*!
  @brief
    Returns the row of the requested index.
  */
  Vector4D&       Matrix4D::operator [] (unsigned row)
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns the row of the requested index.
  */
  const Vector4D& Matrix4D::operator [] (unsigned row) const
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns this matrix plus rhs.
  */
  Matrix4D Matrix4D::operator + (const Matrix4D& rhs) const
  {
    return Matrix4D(m_Rows[0] + rhs.m_Rows[0],
                    m_Rows[1] + rhs.m_Rows[1],
                    m_Rows[2] + rhs.m_Rows[2],
                    m_Rows[3] + rhs.m_Rows[3]);
  }

  /*!
  @brief
    Returns this matrix minus rhs.
  */
  Matrix4D Matrix4D::operator - (const Matrix4D& rhs) const
  {
    return Matrix4D(m_Rows[0] - rhs.m_Rows[0],
                    m_Rows[1] - rhs.m_Rows[1],
                    m_Rows[2] - rhs.m_Rows[2],
                    m_Rows[3] - rhs.m_Rows[3]);
  }

  /*!
  @brief
    Returns this matrix concatinated with rhs.
  */
  Matrix4D Matrix4D::operator * (const Matrix4D& rhs) const
  {
    Matrix4D m;

    m.m_Rows[0][0] = m_Rows[0][0] * rhs.m_Rows[0][0] + m_Rows[0][1] * rhs.m_Rows[1][0] + m_Rows[0][2] * rhs.m_Rows[2][0] + m_Rows[0][3] * rhs.m_Rows[3][0];
    m.m_Rows[0][1] = m_Rows[0][0] * rhs.m_Rows[0][1] + m_Rows[0][1] * rhs.m_Rows[1][1] + m_Rows[0][2] * rhs.m_Rows[2][1] + m_Rows[0][3] * rhs.m_Rows[3][1];
    m.m_Rows[0][2] = m_Rows[0][0] * rhs.m_Rows[0][2] + m_Rows[0][1] * rhs.m_Rows[1][2] + m_Rows[0][2] * rhs.m_Rows[2][2] + m_Rows[0][3] * rhs.m_Rows[3][2];
    m.m_Rows[0][3] = m_Rows[0][0] * rhs.m_Rows[0][3] + m_Rows[0][1] * rhs.m_Rows[1][3] + m_Rows[0][2] * rhs.m_Rows[2][3] + m_Rows[0][3] * rhs.m_Rows[3][3];

    m.m_Rows[1][0] = m_Rows[1][0] * rhs.m_Rows[0][0] + m_Rows[1][1] * rhs.m_Rows[1][0] + m_Rows[1][2] * rhs.m_Rows[2][0] + m_Rows[1][3] * rhs.m_Rows[3][0];
    m.m_Rows[1][1] = m_Rows[1][0] * rhs.m_Rows[0][1] + m_Rows[1][1] * rhs.m_Rows[1][1] + m_Rows[1][2] * rhs.m_Rows[2][1] + m_Rows[1][3] * rhs.m_Rows[3][1];
    m.m_Rows[1][2] = m_Rows[1][0] * rhs.m_Rows[0][2] + m_Rows[1][1] * rhs.m_Rows[1][2] + m_Rows[1][2] * rhs.m_Rows[2][2] + m_Rows[1][3] * rhs.m_Rows[3][2];
    m.m_Rows[1][3] = m_Rows[1][0] * rhs.m_Rows[0][3] + m_Rows[1][1] * rhs.m_Rows[1][3] + m_Rows[1][2] * rhs.m_Rows[2][3] + m_Rows[1][3] * rhs.m_Rows[3][3];

    m.m_Rows[2][0] = m_Rows[2][0] * rhs.m_Rows[0][0] + m_Rows[2][1] * rhs.m_Rows[1][0] + m_Rows[2][2] * rhs.m_Rows[2][0] + m_Rows[2][3] * rhs.m_Rows[3][0];
    m.m_Rows[2][1] = m_Rows[2][0] * rhs.m_Rows[0][1] + m_Rows[2][1] * rhs.m_Rows[1][1] + m_Rows[2][2] * rhs.m_Rows[2][1] + m_Rows[2][3] * rhs.m_Rows[3][1];
    m.m_Rows[2][2] = m_Rows[2][0] * rhs.m_Rows[0][2] + m_Rows[2][1] * rhs.m_Rows[1][2] + m_Rows[2][2] * rhs.m_Rows[2][2] + m_Rows[2][3] * rhs.m_Rows[3][2];
    m.m_Rows[2][3] = m_Rows[2][0] * rhs.m_Rows[0][3] + m_Rows[2][1] * rhs.m_Rows[1][3] + m_Rows[2][2] * rhs.m_Rows[2][3] + m_Rows[2][3] * rhs.m_Rows[3][2];

    m.m_Rows[3][0] = m_Rows[3][0] * rhs.m_Rows[0][0] + m_Rows[3][1] * rhs.m_Rows[1][0] + m_Rows[3][2] * rhs.m_Rows[2][0] + m_Rows[3][3] * rhs.m_Rows[3][0];
    m.m_Rows[3][1] = m_Rows[3][0] * rhs.m_Rows[0][1] + m_Rows[3][1] * rhs.m_Rows[1][1] + m_Rows[3][2] * rhs.m_Rows[2][1] + m_Rows[3][3] * rhs.m_Rows[3][1];
    m.m_Rows[3][2] = m_Rows[3][0] * rhs.m_Rows[0][2] + m_Rows[3][1] * rhs.m_Rows[1][2] + m_Rows[3][2] * rhs.m_Rows[2][2] + m_Rows[3][3] * rhs.m_Rows[3][2];
    m.m_Rows[3][3] = m_Rows[3][0] * rhs.m_Rows[0][3] + m_Rows[3][1] * rhs.m_Rows[1][3] + m_Rows[3][2] * rhs.m_Rows[2][3] + m_Rows[3][3] * rhs.m_Rows[3][3];

    return m;
  }

  /*!
  @brief
    Returns the rhs vector transformed by this matrix.
  */
  Vector4D Matrix4D::operator * (const Vector4D& rhs) const
  {
    return Vector4D(m_Rows[0] * rhs,
                    m_Rows[1] * rhs,
                    m_Rows[2] * rhs,
                    m_Rows[3] * rhs);
  }

  /*!
  @brief
    Returns this matrix scaled by rhs.
  */
  Matrix4D Matrix4D::operator * (float rhs)           const
  {
    return Matrix4D(m_Rows[0] * rhs,
                    m_Rows[1] * rhs,
                    m_Rows[2] * rhs,
                    m_Rows[3] * rhs);
  }

  /*!
  @brief
    Returns this matrix scaled by one over rhs.
  */
  Matrix4D Matrix4D::operator / (float rhs)           const
  {
    return Matrix4D(m_Rows[0] / rhs,
                    m_Rows[1] / rhs,
                    m_Rows[2] / rhs,
                    m_Rows[3] / rhs);
  }

  /*!
  @brief
    Returns true if this matrix is equal to rhs.
  */
  bool Matrix4D::operator == (const Matrix4D& rhs) const
  {
    return (m_Rows[0] == rhs.m_Rows[0] &&
            m_Rows[1] == rhs.m_Rows[1] &&
            m_Rows[2] == rhs.m_Rows[2] &&
            m_Rows[3] == rhs.m_Rows[3] );
  }

  /*!
  @brief
    Returns true if this matrix is not equal to rhs.
  */
  bool Matrix4D::operator != (const Matrix4D& rhs) const
  {
    return (m_Rows[0] != rhs.m_Rows[0] ||
            m_Rows[1] != rhs.m_Rows[1] ||
            m_Rows[2] != rhs.m_Rows[2] ||
            m_Rows[3] != rhs.m_Rows[3] );
  }

  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix4D::Set           (float m00, float m01, float m02, float m03,
                                        float m10, float m11, float m12, float m13,
                                        float m20, float m21,float  m22, float m23,
                                        float m30, float m31, float m32, float m33)
  {
    m_Rows[0].Set(m00, m01, m02, m03);
    m_Rows[1].Set(m10, m11, m12, m13);
    m_Rows[2].Set(m20, m21, m22, m23);
    m_Rows[3].Set(m30, m31, m32, m33);
  }

  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix4D::Set           (const Vector4D &row0,
                                        const Vector4D &row1,
                                        const Vector4D &row2,
                                        const Vector4D &row3)
  {
    m_Rows[0].Set(row0);
    m_Rows[1].Set(row1);
    m_Rows[2].Set(row2);
    m_Rows[3].Set(row3);
  }

  /*!
  @brief
    Sets this matrix to the given data.
  */
  void         Matrix4D::Set           (const Matrix4D& source)
  {
    m_Rows[0].Set(source.m_Rows[0]);
    m_Rows[1].Set(source.m_Rows[1]);
    m_Rows[2].Set(source.m_Rows[2]);
    m_Rows[3].Set(source.m_Rows[3]);
  }

  /*!
  @brief
    Inverts this matrix.
  */
  void         Matrix4D::Invert        ()
  {
    //@todo: Implement Me!
  }

  /*!
  @brief
    Transposes this matrix.
  */
  void         Matrix4D::Transpose     ()
  {
    float temp;

    temp         = m_Rows[0][1];
    m_Rows[0][1] = m_Rows[1][0];
    m_Rows[1][0] = temp;

    temp         = m_Rows[0][2];
    m_Rows[0][2] = m_Rows[2][0];
    m_Rows[2][0] = temp;

    temp         = m_Rows[0][3];
    m_Rows[0][3] = m_Rows[3][0];
    m_Rows[3][0] = temp;

    temp         = m_Rows[1][2];
    m_Rows[1][2] = m_Rows[2][1];
    m_Rows[2][1] = temp;

    temp         = m_Rows[1][3];
    m_Rows[1][3] = m_Rows[3][1];
    m_Rows[3][1] = temp;

    temp         = m_Rows[2][3];
    m_Rows[2][3] = m_Rows[3][2];
    m_Rows[3][2] = temp;
  }

  /*!
  @brief
    Returns the determinant of this matrix.
  */
  float        Matrix4D::Determinant   ()                                       const
  {
    //@todo: Implement Me!
    return 0;
  }

  /*!
  @brief
    Returns the inverse of this matrix.
  */
  Matrix4D     Matrix4D::Inverse       ()                                       const
  {
    //@todo: Implement Me!
    return Matrix4D();
  }

  /*!
  @brief
    Returns the transpose of this matrix.
  */
  Matrix4D     Matrix4D::Transposed    ()                                       const
  {
    return Matrix4D(m_Rows[0][0], m_Rows[1][0], m_Rows[2][0], m_Rows[3][0],
                    m_Rows[0][1], m_Rows[1][1], m_Rows[2][1], m_Rows[3][1],
                    m_Rows[0][2], m_Rows[1][2], m_Rows[2][2], m_Rows[3][2],
                    m_Rows[0][3], m_Rows[1][3], m_Rows[2][3], m_Rows[3][3]);
  }

  /*!
  @brief
    Calculates the determinant and returns true if it is not equal to zero,
    within some tolerance.
  */
  bool         Matrix4D::IsInvertable  (float tolerance) const
  {
    return !MathUtility::FloatEqualsZero(Determinant(), tolerance);
  }

  /*!
  @brief
    Returns the specified row in vector form.
  */
  Vector4D     Matrix4D::Row           (unsigned row)                           const
  {
    return m_Rows[row];
  }

  /*!
  @brief
    Returns the specified column in vector form.
  */
  Vector4D     Matrix4D::Column        (unsigned column)                        const
  {
    return Vector4D(m_Rows[0][column],
                    m_Rows[1][column],
                    m_Rows[2][column],
                    m_Rows[3][column]);
  }

  /*!
  @brief
    Returns rhs scaled by lhs.
  */
  Matrix4D operator * (float lhs, const Matrix4D& rhs)
  {
    return Matrix4D(lhs * rhs.m_Rows[0],
                    lhs * rhs.m_Rows[1],
                    lhs * rhs.m_Rows[2],
                    lhs * rhs.m_Rows[3]);
  }

}//namespace VectorTypes
